import re
import syms
import copy
from Odict import odict

import pprint
pretty = pprint.PrettyPrinter(indent=1)

def get_line_number(original, position):
   return len(original[0:position].split('\n'))

class Parsed(object): 
      def __init__(self, obj, *args, **kwargs):
          self.type = obj.parser_name
          self.nodes = [node for node in args if node]
          self.value = kwargs.get('value')

      def is_terminal(self):
          if self.nodes:
              return False
          return True

      def to_data(self):
          if self.is_terminal():
              if self.value is not None:
                  return '<' + self.type + ': ' + self.value + '>'
              else:
                  return '<' + self.type + '>'
          else:
              return ( self.type, [ to_data(node) for node in self.nodes ])

      def __repr__(self):
          return pretty.pformat(self.to_data())

def to_data(obj):
    if hasattr(obj, 'to_data'):
        return obj.to_data()
    elif isinstance(obj, list):
        return [ to_data(ele) for ele in obj ]
    elif isinstance(obj, dict):
        return dict( [ (key, to_data(value)) for key, value in obj.items() ] )
    elif isinstance(obj, tuple):
        return tuple( [ to_data(ele) for ele in obj ] )
    return obj

class ParserPointer(syms.symbol):

    def parse(self, input):
        return self.parser.parse(input)

    def set_parser(self, parser):
        self._parser = parser

    def check_parser(self):
        if hasattr(self,'_parser'):
            return self._parser
        else:
            raise Exception('Symbol '+self.name+' has no parser assigned')

    parser = property(fget=check_parser, fset=set_parser)

    def get_parser_name(self):
        return self.name

    parser_name = property(fget=get_parser_name);

    def __call__(self, *args):
        if hasattr(self, '_parser'):
            return self.parser(*args)
        else:
            return RepeatFactory(self, *args)

syms.set_default(ParserPointer)

class Token(Parsed):
    def __init__(self, name, value=None):
        self.type = name
        self.nodes = []
        self.value = value
        self.parser_name = name

    def parse(self, input):
       if input[0].type == self.type:
          return (input[0], 1)
       return False

class AST(Parsed):
    def __init__(self, name, **kwargs):
        self.type = name
        self.keys = []
        self.nodes = []
        for key in kwargs:
            self.__dict__[key] = kwargs[key]
            self.keys.append(key)

    def to_data(self):
        out_list = [ self.type ]
        for key in self.keys:
            out_list += [ ( key, to_data(self.__dict__[key]) ) ]
        return tuple(out_list)
                  

def ParsedF(obj, *args, **kwargs):
    """Factory Function for the Parsed object"""
    
    new = Parsed(obj, *args, **kwargs)

    if hasattr(obj, '_handler'):
        ret_val = getattr(obj, '_handler')(new)
        if ret_val is not None:
            return ret_val
    return new

class ParserClass(object):

    def __call__(self, *args):
        return RepeatFactory(self, *args)

def RepeatFactory(self, *args):

    def make_dct(min=0,max=None):
        dct = {'min' : min, 'item': self}
        if max:
            dct['max']=max
        return dct
     
    if len(args)==0:
        name = get_name(self.parser_name + '__many')
    else:
        if isinstance(args[0], str):
            name=args[0]
            args = args[1:]
        else:
            name=get_name(self.parser_name + '__many' + '__'.join(args))

    return Repeat(name, **make_dct(*args))


class Empty(ParserClass):
    def __init__(self, name='Empty'):
        self.parser_name = name
    def parse(self, input):
        return Token(self.parser_name), 0

EMPTY = Empty()

class Node(ParserClass):    
    
    def __init__(self, name, regexp, has_value=False, ignore_groups=False, ignore_case=False):
        self.parser_name = name
        flags = re.DOTALL
        if ignore_case:
            flags |= re.IGNORECASE
        self.regexp = re.compile('^'+regexp, flags)
        self.has_value = has_value
        self.ignore_groups = ignore_groups

    def parse(self, input):
        match_obj = self.regexp.match(input)
        if match_obj:
            if self.has_value:
                if not self.ignore_groups and match_obj.groups():
                    value = match_obj.groups()[0]
                else:
                    value = input[match_obj.start():match_obj.end()]
                value = value
            else:
                value = None
            return ParsedF(self,value=value), match_obj.end()
        else:
            return False

def T(name, regexp, has_value=True):
    return Node(name, regexp,has_value=has_value)

lit = re.escape

class Choice(ParserClass):
    def __init__(self, name, choices):
        self.parser_name=name
        self.choices=choices

    def parse(self, input):
        for choice in self.choices:
            parse_result = choice.parse(input)
            if parse_result:
                return ParsedF(self, parse_result[0]), parse_result[1]
        return False

def C(name, *args, **kwargs):
    choices = [ factory(arg, name+'_'+str(cnt)) for cnt, arg in enumerate(args) ]
    for _name, parser in odict(kwargs).items():
        choices += [ factory(parser, _name) ]
    return Choice(name, choices)

class Repeat(ParserClass):

    def __init__(self, name, item, min=0, max=None):
        self.parser_name = name
        self.item = item
        self.min = min
        self.max = max
        self.has_max = (max is not None)
        self.length = 0

    def parse(self, input):
        success = True
        results = []
        self.length = 0
        while success and not self.done(results):
            result = self.item.parse(input)
            if result:
                results.append(result[0])
                input = input[result[1]:]
                self.length += result[1]
            else:
                success=False
        if len(results) >= self.min:
            return ParsedF(self, *results), self.length
        return False

    def done(self, lst):
        if self.has_max:
            return (len(lst) >= self.max)

class Rule(ParserClass):

    def __init__(self, name, rule):
        self.parser_name = name
        self.rule = R(None, rule, True)

    def parse(self, input):
        results = []
        chars = 0
        for item in self.rule:
            result = item.parse(input)
            if result:
                results.append(result[0])
                input = input[result[1]:]
                chars += result[1]
            else:
                return False
        return ParsedF(self, *results), chars

def R(name, parsers, root=False):
    rule = [ factory(parser) for parser in parsers ]
    if root:
        return rule
    return Rule(name, rule)    

def L(*parsers):
    name = parsers[0].parser_name
    for parser in parsers[1:]:
        name += '__' + parser.parser_name 
    return R(get_name(name), parsers)

nameless_parsers = 0
semi_nameless = {}
def get_name(name=None):
    global nameless_parsers
    global semi_nameless
    if name:
        if semi_nameless.has_key(name):
            semi_nameless[name] += 1
        else:
            semi_nameless[name] = 0    
        return name + '_' + str(semi_nameless[name])
    else:
        nameless_parsers += 1
        return '_' + str(nameless_parsers)

def reset_names():
    global nameless_parsers
    global semi_nameless
    nameless_parsers = 0
    semi_nameless = {}

def factory(arg, _name=None, **kwarg):
    has_value = (_name is not None)
    if _name is None:
        _name = get_name()
    if isinstance(arg, str):
       return T(_name, arg, has_value)
    if isinstance(arg, list):
       return R(_name, arg)
    if isinstance(arg, tuple):
       return C(_name, *arg, **kwarg)
    for parser_class in [ParserClass, syms.symbol, Token]:
        if isinstance(arg, parser_class):
            return arg
    raise Exception('Parser unbuildable:' + repr(arg))

_regexp = re.compile('^_')
def D(sym, *arg, **kwargs):
   
    #seperate out the keywords that begin with '_'
    _kwargs = {}
    for key in kwargs:
        if _regexp.match(key):
            _kwargs[key] = kwargs[key]
    for key in _kwargs:
        del kwargs[key]

    if len(arg)== 1 and len(kwargs)==0:
        arg = arg[0]
    if isinstance(arg, syms.symbol):
        grammer = copy.copy(arg.parser)
        grammer.parser_name = sym.name
    else:     
        grammer = factory(arg, sym.name, **kwargs)
    sym.set_parser(grammer)         
    if _kwargs.has_key('_handler'):
        grammer._handler = _kwargs['_handler']
